/**
 * @file test_model.cpp
 * @author Young_jam (Young_jam2018@outlook.com)
 * @brief 测试鼠标事件
 * @date 2023/01/17
 * @version 1.0
 */
#include "c_defines.h"
#include "glut_win.h"
#include "model.h"
#include "shader_mgr.h"
#include <GL/freeglut_std.h>
#include <GL/gl.h>
#include <GL/glext.h>
#include <GLES3/gl3.h>
#include <glm/detail/type_vec.hpp>
#include <glm/ext.hpp>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <iostream>
#include <memory>
#include <unistd.h>

using namespace std;

shared_ptr<CModel> g_model;

bool gLeftButtonDown = false;
bool gRightButtonDown = false;

int gMouseX = 0;
int gMouseY = 0;

GLfloat gRotateX = 0.f;
GLfloat gRotateY = 0.f;

void Init(void)
{
    glClearColor(.22f, .21f, .23f, 1.f);

    glEnable(GL_DEPTH_TEST);

    // 启用裁剪模式
    glEnable(GL_CULL_FACE);

    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

    auto shader = CShaderManager::GetInstance().CreateNewShader("model");
    if (!shader->LoadShader("../shader/model0.vert", "../shader/model0.frag", 1, 0, "vVertexs"))
    {
        ERROR("load shader failed!");
        exit(EXIT_FAILURE);
    }

    g_model = make_shared<CModel>();
    g_model->LoadModel("../resource/I6/irizar_I6.3ds");
}

void Display()
{
    static auto shader = CShaderManager::GetInstance().GetShader("model");

    static glm::mat4 projection = glm::perspective(glm::radians(75.f), GLfloat(800) / GLfloat(600), 1.f, 100000.f);
    static glm::mat4 view = glm::lookAt(glm::vec3(0.f, 15.f, -20.f),     // 眼睛在哪里
                                        glm::vec3(0.f),                  // 眼睛看向哪里
                                        glm::vec3(0.f, 1000.f, -20.f));  // 头部指向哪里
    static glm::mat4 model = glm::scale(glm::mat4(1.f), glm::vec3(1.f));
    model = glm::rotate(model, gRotateX, glm::vec3(0.f, 1.f, 0.f));
    // model = glm::rotate(model, gRotateY, glm::vec3(0.f, 1.f, 0.f));

    gRotateX = 0.f;
    gRotateY = 0.f;

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    shader->Enable();

    shader->SetUniformMatrix4fv("projection", glm::value_ptr(projection));
    shader->SetUniformMatrix4fv("view", glm::value_ptr(view));
    shader->SetUniformMatrix4fv("model", glm::value_ptr(model));

    g_model->Draw();

    shader->Disable();

    sleep(1);
    glutSwapBuffers();
}

/**
 * @brief 处理鼠标单击事件
 * @param button [in] 鼠标上的键
 * @param state [in] 键的状态
 * @param x [in] 鼠标位置
 * @param y [in] 鼠标位置
 */
void ClickMouseEvent(int button, int state, int x, int y)
{
    if (GLUT_LEFT_BUTTON == button)
    {
        if (GLUT_DOWN == state)
            gLeftButtonDown = true;
        else if (GLUT_UP == state)
            gLeftButtonDown = false;
    }

    if (GLUT_RIGHT_BUTTON == button)
    {
        if (GLUT_DOWN == state)
            gRightButtonDown = true;
        else if (GLUT_UP == state)
            gRightButtonDown = false;
    }
    gMouseX = x;
    gMouseY = y;
}

/**
 * @brief 处理鼠标移动事件
 * @param x [in] 鼠标位置
 * @param y [in] 鼠标位置
 */
void MoveMouseEvent(int x, int y)
{
    int x_offset = 0;
    int y_offset = 0;

    if (gLeftButtonDown)
    {
        x_offset = x - gMouseX;
        y_offset = y - gMouseY;
    }
    if (gRightButtonDown)
    {
        x_offset = gMouseX - x;
        y_offset = y - gMouseY;
    }

    gRotateX = GLfloat(x_offset) / 800.f * 360.f;
    gRotateY = GLfloat(y_offset) / 600.f * 360.f;

    INFO("rotate: %f %f\n", gRotateX, gRotateY);

    gMouseX = x;
    gMouseY = y;

    glutPostRedisplay();
}

int main(int argc, char **argv)
{
    CGlutWindow window("shader test");

    window.Init(&argc, argv, GLUT_RGBA | GLUT_DOUBLE, 640, 320, 800, 600);

    Init();

    window.RegisterCallbackFunc([]() {
        glutDisplayFunc(Display);
        glutIdleFunc(Display);
        glutMouseFunc(ClickMouseEvent);
        glutMotionFunc(MoveMouseEvent);
    });

    window.MainLoop();

    return 0;
}